//#define TRUE (0==0)
//#define FALSE (!TRUE)

// finding a element by index from an array.
static int getArrayValueByIndex(zval array, long index, zval **dest) {
	zval **dest1;
	TSRMLS_FETCH();

	if (Z_TYPE(array)!=IS_ARRAY) return FALSE;
	if (zend_hash_index_find(Z_ARRVAL(array),index, (void **)&dest1)==FAILURE) {
		php_error(E_WARNING, "%s() unable to find %d in array",
					get_active_function_name(TSRMLS_C),index);
		return FALSE;
	}
	*dest=*dest1;
	return TRUE;
}

// finding a element by string key from an array.
static int getArrayValueByString(zval array, char *key, zval **dest) {
	long key_length=0;
	zval **dest1;
	TSRMLS_FETCH();

	if (Z_TYPE(array)!=IS_ARRAY) return FALSE;
	key_length=strlen(key);
	if (key && zend_hash_find(Z_ARRVAL(array),key,key_length+1,(void **)&dest1)==FAILURE) {
		php_error(E_WARNING, "%s() unable to find %s in array",
					get_active_function_name(TSRMLS_C),key);
		return FALSE;
	}
	*dest=*dest1;
	return TRUE;
}

static void dumpaVar(zval uservar) {
    TSRMLS_FETCH();

	php_printf("Yououoo\n");
	switch (Z_TYPE(uservar)) {
		case IS_NULL:
			php_printf("NULL ");
			break;
		case IS_BOOL:
			php_printf("Boolean: %s ", Z_LVAL(uservar) ? "TRUE" : "FALSE");
			break;
		case IS_LONG:
			php_printf("Long: %ld ", Z_LVAL(uservar));
			break;
		case IS_DOUBLE:
			php_printf("Double: %f ", Z_DVAL(uservar));
			break;
		case IS_STRING:
			php_printf("String: ");
			PHPWRITE(Z_STRVAL(uservar), Z_STRLEN(uservar));
			php_printf(" ");
			break;
		case IS_RESOURCE:
			php_printf("Resource ");
			break;
		case IS_ARRAY:
			php_printf("Array ");
			break;
		case IS_OBJECT:
			php_printf("Object ");
			break;
		default:
			php_printf("Unknown ");
	}
}

// counting
static ulong getArrayCount(zval array) {
	if (Z_TYPE(array)!=IS_ARRAY) return FALSE;
	return zend_hash_next_free_element(Z_ARRVAL(array));
}

int XX(void) {
	php_printf("Hello world");
	return 1;
}
void mysdl_error(const char *msg) {
    TSRMLS_FETCH();
	if (MYGLOBALS(show_sdl_errors)) {
		php_error(E_WARNING,"function:%s, error in %s: SDL Error: %s",
			get_active_function_name(TSRMLS_C),msg,SDL_GetError());
	}
}
//SDL_Rect->Array.
static void rect2array(SDL_Rect r, zval *a)
{
	array_init(a);
	add_assoc_long(a, "x", r.x);
	add_assoc_long(a, "y", r.y);
	add_assoc_long(a, "w", r.w);
	add_assoc_long(a, "h", r.h);
}

static int array2rect(zval srcrect, SDL_Rect *r) {
	zval *handle;
	if (!getArrayValueByString(srcrect,"x",&handle)) {
		r->x=0;
	} else {
		r->x=Z_LVAL_P(handle);
	}
	if (!getArrayValueByString(srcrect,"y",&handle)) {
		r->y=0;
	} else {
		r->y=Z_LVAL_P(handle);
	}
	if (!getArrayValueByString(srcrect,"w",&handle)) {
		r->w=0;
	} else {
		r->w=Z_LVAL_P(handle);
	}
	if (!getArrayValueByString(srcrect,"h",&handle)) {
		r->h=0;
	} else {
		r->h=Z_LVAL_P(handle);
	}

    return 1;
}
//SDL_PixelFormat -> Array
static void pf2array(SDL_PixelFormat *pixelformat, zval *pixelformat_array TSRMLS_DC)
{
	zval *palette, *colors, *color;
	int handle, i;

	handle = zend_list_insert(pixelformat, le_pixelformat);

	array_init(pixelformat_array);
	add_assoc_resource(pixelformat_array, "handle", handle);
	zend_list_addref(handle);

	add_assoc_long(pixelformat_array, "BitsPerPixel", pixelformat->BitsPerPixel);
	add_assoc_long(pixelformat_array, "BytesPerPixel", pixelformat->BytesPerPixel);
	add_assoc_long(pixelformat_array, "Rmask", pixelformat->Rmask);
	add_assoc_long(pixelformat_array, "Gmask", pixelformat->Gmask);
	add_assoc_long(pixelformat_array, "Bmask", pixelformat->Bmask);
	add_assoc_long(pixelformat_array, "Amask", pixelformat->Amask);
	add_assoc_long(pixelformat_array, "Rshift", pixelformat->Rshift);
	add_assoc_long(pixelformat_array, "Gshift", pixelformat->Gshift);
	add_assoc_long(pixelformat_array, "Bshift", pixelformat->Bshift);
	add_assoc_long(pixelformat_array, "Ashift", pixelformat->Ashift);
	add_assoc_long(pixelformat_array, "Rloss", pixelformat->Rloss);
	add_assoc_long(pixelformat_array, "Gloss", pixelformat->Gloss);
	add_assoc_long(pixelformat_array, "Bloss", pixelformat->Bloss);
	add_assoc_long(pixelformat_array, "Aloss", pixelformat->Aloss);
	add_assoc_long(pixelformat_array, "colorkey", pixelformat->colorkey);
	add_assoc_long(pixelformat_array, "alpha", pixelformat->alpha);

	if (pixelformat->palette == NULL) {
		add_assoc_null(pixelformat_array, "palette");
	} else {
		MAKE_STD_ZVAL(palette);
		array_init(palette);
		MAKE_STD_ZVAL(colors);
		add_assoc_long(palette, "ncolors", pixelformat->palette->ncolors);
		array_init(colors);

		for(i=0; i < pixelformat->palette->ncolors; i++)
		{
			MAKE_STD_ZVAL(color);
			array_init(color);
			add_assoc_long(color, "r", pixelformat->palette->colors[i].r);
			add_assoc_long(color, "g", pixelformat->palette->colors[i].g);
			add_assoc_long(color, "b", pixelformat->palette->colors[i].b);
			add_next_index_zval(colors, color);
		}
		add_assoc_zval(palette, "colors", colors);
		add_assoc_zval(pixelformat_array, "palette", palette);
	}
}

// SDL_Surface -> Array
static void surf2array(SDL_Surface *surface, zval *surface_array TSRMLS_DC)
{
	zval *format, *rect;
	int handle;

	handle = zend_list_insert(surface, le_surface);

	array_init(surface_array);
	add_assoc_resource(surface_array, "handle", handle);
	zend_list_addref(handle);

	add_assoc_long(surface_array, "flags", surface->flags);
	add_assoc_long(surface_array, "w", surface->w);
	add_assoc_long(surface_array, "h", surface->h);
	add_assoc_long(surface_array, "pitch", surface->pitch);
	add_assoc_long(surface_array, "refcount", surface->refcount);

	MAKE_STD_ZVAL(format);
	pf2array(surface->format, format TSRMLS_CC);
	add_assoc_zval(surface_array, "format", format);

	MAKE_STD_ZVAL(rect);
	rect2array(surface->clip_rect, rect);
	add_assoc_zval(surface_array, "clip_rect", rect);
}

static void videoinfo2array(SDL_VideoInfo *from, zval *to TSRMLS_DC) {
	zval *fmt;
	array_init(to);

	add_assoc_long(to, "hw_available", from->hw_available);
	add_assoc_long(to, "wm_available", from->wm_available);
	add_assoc_long(to, "blit_hw", from->blit_hw);
	add_assoc_long(to, "blit_hw_CC", from->blit_hw_CC);
	add_assoc_long(to, "blit_hw_A", from->blit_hw_A);
	add_assoc_long(to, "blit_sw", from->blit_sw);
	add_assoc_long(to, "blit_sw_CC", from->blit_sw_CC);
	add_assoc_long(to, "blit_sw_A", from->blit_sw_A);
	add_assoc_long(to, "blit_fill", from->blit_fill);
	add_assoc_long(to, "video_mem", from->video_mem);

	MAKE_STD_ZVAL(fmt);
	pf2array(from->vfmt, fmt TSRMLS_CC);
	add_assoc_zval(to, "vfmt", fmt);
}

static void overlay2array(SDL_Overlay *from, zval *to TSRMLS_DC) {
	int handle;

	handle = zend_list_insert(from, le_overlay);

	array_init(to);
	add_assoc_resource(to, "handle", handle);
	zend_list_addref(handle);

	add_assoc_long(to, "format", from->format);
	add_assoc_long(to, "w", from->w);
	add_assoc_long(to, "h", from->h);
	add_assoc_long(to, "planes", from->planes);
	add_assoc_long(to, "hw_overlay", from->hw_overlay);
}

static int event2array(SDL_Event event, zval *event_array TSRMLS_DC)
{
	zval *active;
	zval *key, *keysym;
	zval *motion;
	zval *button;
	zval *jaxis;
	zval *jball;
	zval *jhat;
	zval *jbutton;
	zval *resize;
	zval *quit;
	zval *user;
	zval *syswm;

	switch (event.type) {
	case SDL_ACTIVEEVENT:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_ActiveEvent active
		MAKE_STD_ZVAL(active);
		array_init(active);
		add_assoc_long(active, "type", event.active.type);
		add_assoc_long(active, "gain", event.active.gain);
		add_assoc_long(active, "state", event.active.state);
		add_assoc_zval(event_array, "active", active);
		break;
	case SDL_KEYDOWN:
	case SDL_KEYUP:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_KeyboardEvent key
		MAKE_STD_ZVAL(key);
		array_init(key);
		add_assoc_long(key, "type", event.key.type);
		add_assoc_long(key, "state", event.key.state);
		MAKE_STD_ZVAL(keysym); // key.keysym
		array_init(keysym);
		add_assoc_long(keysym, "scancode", event.key.keysym.scancode);
		add_assoc_long(keysym, "sym", event.key.keysym.sym);
		add_assoc_long(keysym, "mod", event.key.keysym.mod);
		add_assoc_long(keysym, "unicode", event.key.keysym.unicode);
		add_assoc_zval(key, "keysym", keysym);
		add_assoc_zval(event_array, "key", key);
		break;
	case SDL_MOUSEMOTION:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_MouseMotionEvent motion
		MAKE_STD_ZVAL(motion);
		array_init(motion);
		add_assoc_long(motion, "type", event.motion.type);
		add_assoc_long(motion, "state", event.motion.state);
		add_assoc_long(motion, "x", event.motion.x);
		add_assoc_long(motion, "y", event.motion.y);
		add_assoc_long(motion, "xrel", event.motion.xrel);
		add_assoc_long(motion, "yrel", event.motion.yrel);
		add_assoc_zval(event_array, "motion", motion);
		break;
	case SDL_MOUSEBUTTONDOWN:
	case SDL_MOUSEBUTTONUP:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_MouseButtonEvent button
		MAKE_STD_ZVAL(button);
		array_init(button);
		add_assoc_long(button, "type", event.button.type);
		add_assoc_long(button, "button", event.button.button);
		add_assoc_long(button, "state", event.button.state);
		add_assoc_long(button, "x", event.button.x);
		add_assoc_long(button, "y", event.button.y);
		add_assoc_zval(event_array, "button", button);
		break;
	case SDL_JOYAXISMOTION:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_JoyAxisEvent jaxis
		MAKE_STD_ZVAL(jaxis);
		array_init(jaxis);
		add_assoc_long(jaxis, "type", event.jaxis.type);
		add_assoc_long(jaxis, "which", event.jaxis.which);
		add_assoc_long(jaxis, "axis", event.jaxis.axis);
		add_assoc_long(jaxis, "value", event.jaxis.value);
		add_assoc_zval(event_array, "jaxis", jaxis);
		break;
	case SDL_JOYBALLMOTION:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_JoyBallEvent jball
		MAKE_STD_ZVAL(jball);
		array_init(jball);
		add_assoc_long(jball, "type", event.jball.type);
		add_assoc_long(jball, "which", event.jball.which);
		add_assoc_long(jball, "ball", event.jball.ball);
		add_assoc_long(jball, "xrel", event.jball.xrel);
		add_assoc_long(jball, "yrel", event.jball.yrel);
		add_assoc_zval(event_array, "jball", jball);
		break;
	case SDL_JOYHATMOTION:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_JoyHatEvent jhat
		MAKE_STD_ZVAL(jhat);
		array_init(jhat);
		add_assoc_long(jhat, "type", event.jhat.type);
		add_assoc_long(jhat, "which", event.jhat.which);
		add_assoc_long(jhat, "hat", event.jhat.hat);
		add_assoc_long(jhat, "value", event.jhat.value);
		add_assoc_zval(event_array, "jhat", jhat);
		break;
	case SDL_JOYBUTTONDOWN:
	case SDL_JOYBUTTONUP:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_JoyButtonEvent jbutton
		MAKE_STD_ZVAL(jbutton);
		array_init(jbutton);
		add_assoc_long(jbutton, "type", event.jbutton.type);
		add_assoc_long(jbutton, "which", event.jbutton.which);
		add_assoc_long(jbutton, "button", event.jbutton.button);
		add_assoc_long(jbutton, "state", event.jbutton.state);
		add_assoc_zval(event_array, "jbutton", jbutton);
		break;
	case SDL_VIDEORESIZE:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_ResizeEvent resize
		MAKE_STD_ZVAL(resize);
		array_init(resize);
		add_assoc_long(resize, "type", event.resize.type);
		add_assoc_long(resize, "w", event.resize.w);
		add_assoc_long(resize, "h", event.resize.h);
		add_assoc_zval(event_array, "resize", resize);
		break;
	case SDL_QUIT:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_QuitEvent quit
		MAKE_STD_ZVAL(quit);
		array_init(quit);
		add_assoc_long(quit, "type", event.quit.type);
		add_assoc_zval(event_array, "quit", quit);
		break;
	case SDL_USEREVENT:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_UserEvent user
		MAKE_STD_ZVAL(user);
		array_init(user);
		add_assoc_long(user, "code", event.user.code);
		//add_assoc_zval(user, "data", event.user.data1);
		if (event.user.data1!=NULL) {
			add_assoc_zval(user, "data1", (zval *)event.user.data1);
		}

		add_assoc_zval(event_array, "user", user);
		break;
	case SDL_SYSWMEVENT:
		array_init(event_array);
		add_assoc_long(event_array, "type", event.type);

		// SDL_SywWMEvent syswm
		MAKE_STD_ZVAL(syswm);
		array_init(syswm);
		add_assoc_zval(event_array, "syswm", syswm);
		break;
	/* Silently ignore the following events as the do not have any further
	 * information. */
	case SDL_VIDEOEXPOSE:
		break;
	default:
		/*
		php_error(E_WARNING, "%s() unknown event type %d",
			  get_active_function_name(TSRMLS_C), event.type);
		*/
		return 0;
	}
	return 1;
}
static int array2event(zval from TSRMLS_DC, SDL_Event *to) {
	int type;
	zval *p,*p1,*p2,*p3,*p4,*p5,*p6,*p7,*p8;

	getArrayValueByString(from,"type",&p);
	type=Z_LVAL_P(p);
	switch(type) {
	case SDL_ACTIVEEVENT:
	    to->type=type;
	    getArrayValueByString(from,"active",&p1);
	    getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"gain",&p3);
		getArrayValueByString(*p1,"state",&p4);
		to->active.type=Z_LVAL_P(p2);
		to->active.gain=Z_LVAL_P(p3);
		to->active.state=Z_LVAL_P(p4);
		break;

	case SDL_KEYUP:
	case SDL_KEYDOWN:
	    to->type=type;
	    getArrayValueByString(from,"key",&p1);
	    getArrayValueByString(*p1,"type",&p2);
	    getArrayValueByString(*p1,"state",&p3);
	    getArrayValueByString(*p1,"keysym",&p4);
	    to->key.type=Z_LVAL_P(p2);
	    to->key.state=Z_LVAL_P(p3);
		getArrayValueByString(*p4,"scancode",&p5);
		getArrayValueByString(*p4,"sym",&p6);
		getArrayValueByString(*p4,"mod",&p7);
		getArrayValueByString(*p4,"unicode",&p8);
		to->key.keysym.scancode=(Uint8)Z_LVAL_P(p5);
		to->key.keysym.sym=(SDLKey)Z_LVAL_P(p6);
		to->key.keysym.mod=(SDLMod)Z_LVAL_P(p7);
		to->key.keysym.unicode=(SDLMod)Z_LVAL_P(p8);
		break;

	case SDL_MOUSEMOTION:
	    to->type=type;
		getArrayValueByString(from,"motion",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"state",&p3);
		getArrayValueByString(*p1,"x",&p4);
		getArrayValueByString(*p1,"y",&p5);
		getArrayValueByString(*p1,"xrel",&p6);
		getArrayValueByString(*p1,"yrel",&p7);
		to->motion.type=Z_LVAL_P(p2);
		to->motion.state=Z_LVAL_P(p3);
		to->motion.x=(Uint16)Z_LVAL_P(p4);
		to->motion.y=(Uint16)Z_LVAL_P(p5);
		to->motion.xrel=(Sint16)Z_LVAL_P(p6);
		to->motion.yrel=(Sint16)Z_LVAL_P(p7);
		break;

	case SDL_MOUSEBUTTONUP:
	case SDL_MOUSEBUTTONDOWN:
	    to->type=type;
		getArrayValueByString(from,"button",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"button",&p3);
		getArrayValueByString(*p1,"state",&p4);
		getArrayValueByString(*p1,"x",&p5);
		getArrayValueByString(*p1,"y",&p6);
		to->button.type=Z_LVAL_P(p2);
		to->button.button=(Uint8)Z_LVAL_P(p3);
		to->button.state=(Uint8)Z_LVAL_P(p4);
		to->button.x=(Sint16)Z_LVAL_P(p5);
		to->button.y=(Sint16)Z_LVAL_P(p6);
		break;

	case SDL_JOYAXISMOTION:
	    to->type=type;
	    getArrayValueByString(from,"jaxis",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"which",&p3);
		getArrayValueByString(*p1,"axis",&p4);
		getArrayValueByString(*p1,"value",&p5);
		to->jaxis.type=Z_LVAL_P(p2);
		to->jaxis.which=(Uint8)Z_LVAL_P(p3);
		to->jaxis.axis=(Uint8)Z_LVAL_P(p4);
		to->jaxis.value=(Sint16)Z_LVAL_P(p5);
		break;

	case SDL_JOYBALLMOTION:
	    to->type=type;
		getArrayValueByString(from,"jball",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"which",&p3);
		getArrayValueByString(*p1,"ball",&p4);
		getArrayValueByString(*p1,"xrel",&p5);
		getArrayValueByString(*p1,"yrel",&p6);
		to->jball.type=Z_LVAL_P(p2);
		to->jball.which=(Uint8)Z_LVAL_P(p3);
		to->jball.ball=(Uint8)Z_LVAL_P(p4);
		to->jball.xrel=(Sint16)Z_LVAL_P(p5);
		to->jball.yrel=(Sint16)Z_LVAL_P(p6);
		break;

	case SDL_JOYHATMOTION:
	    to->type=type;
		getArrayValueByString(from,"jhat",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"which",&p3);
		getArrayValueByString(*p1,"hat",&p4);
		getArrayValueByString(*p1,"value",&p5);
		to->jhat.type=Z_LVAL_P(p2);
		to->jhat.which=(Uint8)Z_LVAL_P(p3);
		to->jhat.hat=(Uint8)Z_LVAL_P(p4);
		to->jhat.value=(Uint8)Z_LVAL_P(p5);
		break;

	case SDL_JOYBUTTONUP:
	case SDL_JOYBUTTONDOWN:
	    to->type=type;
		getArrayValueByString(from,"jbutton",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"which",&p3);
		getArrayValueByString(*p1,"button",&p4);
		getArrayValueByString(*p1,"state",&p5);
		to->jbutton.type=Z_LVAL_P(p2);
		to->jbutton.which=(Uint8)Z_LVAL_P(p3);
		to->jbutton.button=(Uint8)Z_LVAL_P(p4);
		to->jbutton.state=(Uint8)Z_LVAL_P(p5);
		break;

	case SDL_VIDEORESIZE:
	    to->type=type;
		getArrayValueByString(from,"resize",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"w",&p3);
		getArrayValueByString(*p1,"h",&p4);
		to->resize.type=Z_LVAL_P(p2);
		to->resize.w=(int)Z_LVAL_P(p3);
		to->resize.h=(int)Z_LVAL_P(p4);
		break;

	case SDL_VIDEOEXPOSE:
		to->type=type;
		//HMMM...
		to->expose.type=SDL_QUIT;
		break;

	case SDL_QUIT:
		to->type=type;
		to->expose.type=SDL_QUIT;
		break;

	case SDL_SYSWMEVENT:
		to->type=type;
		break;

	case SDL_USEREVENT:
		to->type = type;
		getArrayValueByString(from,"user",&p1);
		getArrayValueByString(*p1,"type",&p2);
		getArrayValueByString(*p1,"code",&p3);
		getArrayValueByString(*p1,"data1",&p4);
		//getArrayValueByString(*p1,"data2",&p5);
		to->user.type = Z_LVAL_P(p2);
		to->user.code = (int)Z_LVAL_P(p3);
		to->user.data1 = (void *)p4;
		to->user.data2 = NULL;
		break;
	}

	return 1;
}

// Graphics -> Array
static void graphics2array(gcn::SDLGraphics *graphics, zval *graphics_array TSRMLS_DC)
{
    zval *mTarget, *mColor;
	int handle;

	handle = zend_list_insert(graphics, le_graphics);

	array_init(graphics_array);
	add_assoc_resource(graphics_array, "handle", handle);
	zend_list_addref(handle);

	//add_assoc_bool(graphics_array, "mAlpha", graphics->mAlpha);

	//MAKE_STD_ZVAL(mTarget);
	//surf2array(graphics->mTarget, mTarget TSRMLS_CC);
	//add_assoc_zval(graphics_array, "mTarget", mTarget);

	//MAKE_STD_ZVAL(mColor);
	//add_assoc_bool(mColor, "r", graphics->mColor.r);
	//add_assoc_bool(mColor, "g", graphics->mColor.g);
	//add_assoc_bool(mColor, "b", graphics->mColor.b);
	//add_assoc_bool(mColor, "a", graphics->mColor.a);
	//add_assoc_zval(graphics_array, "mColor", mColor);
}

// Input -> Array
static void input2array(gcn::SDLInput *input, zval *input_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(input, le_input);

	array_init(input_array);
	add_assoc_resource(input_array, "handle", handle);
	zend_list_addref(handle);

	//add_assoc_bool(input_array, "mMouseDown", input->mMouseDown);
	//add_assoc_bool(input_array, "mMouseInWindow", input->mMouseInWindow);
}

// Container -> Array
static void container2array(gcn::Container *container, zval *container_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(container, le_container);

	array_init(container_array);
	add_assoc_resource(container_array, "handle", handle);
	zend_list_addref(handle);

	//add_assoc_bool(container_array, "mOpaque", container->mOpaque);
}

// Font -> Array
static void font2array(gcn::Font *font, zval *font_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(font, le_font);

	array_init(font_array);
	add_assoc_resource(font_array, "handle", handle);
	zend_list_addref(handle);
}

// Label -> Array
static void label2array(gcn::Label *label, zval *label_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(label, le_label);

	array_init(label_array);
	add_assoc_resource(label_array, "handle", handle);
	zend_list_addref(handle);
}

// Button -> Array
static void button2array(gcn::Button *button, zval *button_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(button, le_button);

	array_init(button_array);
	add_assoc_resource(button_array, "handle", handle);
	zend_list_addref(handle);
}

// TextBox -> Array
static void textbox2array(gcn::TextBox *textbox, zval *textbox_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(textbox, le_textbox);

	array_init(textbox_array);
	add_assoc_resource(textbox_array, "handle", handle);
	zend_list_addref(handle);
}

// TextField -> Array
static void textfield2array(gcn::TextField *textfield, zval *textfield_array TSRMLS_DC)
{
	int handle;

	handle = zend_list_insert(textfield, le_textfield);

	array_init(textfield_array);
	add_assoc_resource(textfield_array, "handle", handle);
	zend_list_addref(handle);
}

static int internal_sdl_peep_events(zval *events, int number, int action, int mask) {
	SDL_Event *events_array;
	int result;
	long type;
	zval *p;

	TSRMLS_FETCH();

	int typ1,i;
	typ1=0;

	type=Z_TYPE_P(p);

	switch (action) {
	case SDL_ADDEVENT:
		if (number<1) {
			mysdl_error ("events number <=0");
			return FALSE;
		}
		if (Z_TYPE_P(events)!=IS_ARRAY) {
			mysdl_error ("event parameter must be array");
			return FALSE;
		}

		if (!getArrayValueByIndex (*events,0,&p)) {
			mysdl_error ("Parameter event cannot be an empty array, used with SDL_EVENT");
			return FALSE;
		}

		if (Z_TYPE_P(p)==IS_LONG)
			typ1=1;
		else if (Z_TYPE_P(p)==IS_ARRAY)
			typ1=2;

		switch(typ1) {
		case 1:
			if (number != 1) {
				mysdl_error("SDL_ADDEVENT called with one event but numevent is >1");
				return FALSE;
			}
			events_array = (SDL_Event *)emalloc(number*sizeof(SDL_Event));
			if (!array2event (*events TSRMLS_CC, &(events_array[0]))) {
				efree(events);
				return FALSE;
			}
			break;
		case 2:
			if (getArrayCount (*events)!=number) {
				mysdl_error ("size of array of event parameter must match number param");
				return FALSE;
				events_array = (SDL_Event *)emalloc(number*sizeof(SDL_Event));
				for (i=0;i<number;i++) {
					if (!getArrayValueByIndex (*events,i,&p)) {
						mysdl_error ("Unable to fetch event element from array");
						efree(events_array);
						return FALSE;
					}
					if (Z_TYPE_P(p)!=IS_ARRAY) {
						mysdl_error("Elements of event parameter array must be arrays themselves");
						efree(events_array);
						return FALSE;
					}
					if (!array2event(*p TSRMLS_CC, &(events_array[i]))) {
						efree(events);
						return FALSE;
					}
				}
			}
			break;
		default:
			mysdl_error ("Parameter events,for SDL_ADDEVENT, must be a single event or an array of events");
			return FALSE;
		}
		break;
	case SDL_PEEKEVENT:
	case SDL_GETEVENT:
		{
			if (number < 1) {
				mysdl_error ("Parameter number must be >0 if action is SDL_PEEKEVENT or SDL_GETEVENT");
				return FALSE;
			}
			if (NULL == (events_array = (SDL_Event *)emalloc(number* sizeof(SDL_Event)))) {
				mysdl_error ("Failed to alloc events array");
				return FALSE;
			}
		}
		break;
	default:
		mysdl_error ("Parameter action must be one of SDL_ADDEVENT, SDL_PEEKEVENT or SDL_GETEVENT");
		return FALSE;
	}

	result = SDL_PeepEvents(events_array, number, (SDL_eventaction)action, mask);

	if (result != -1 && events_array  && action != SDL_ADDEVENT) {
		int i;
		zval *tmp;

		/* Now that we have called either SDL_PEEKEVENT or SDL_GETEVENT and no
		 * error occured, we need to return the events. */
		array_init(events);
		for (i = 0; i < result; i++) {
			MAKE_STD_ZVAL(tmp);
			array_init(tmp);
			if (!event2array(events_array[i], tmp TSRMLS_CC)) {
				zval_ptr_dtor(&tmp);
				efree(events_array);
				return FALSE;
			}
			add_next_index_zval(events, tmp);
		}
	}

	if (events_array) {
		efree(events_array);
	}
	return result;
}

static int cdrom2array(SDL_CD *from, zval *to) {
	int cur_track;
	int handle;

	zval *track_arr,*track;

	TSRMLS_FETCH();

	MAKE_STD_ZVAL(track_arr);
	array_init(track_arr);

	for(cur_track=0; cur_track <= SDL_MAX_TRACKS; cur_track++) {
		MAKE_STD_ZVAL(track);
		array_init(track);
		add_assoc_long(track, "id", from->track[cur_track].id);
		add_assoc_long(track, "type", from->track[cur_track].type);
		add_assoc_long(track, "unused", from->track[cur_track].unused);
		add_assoc_long(track, "length", from->track[cur_track].length);
		add_assoc_long(track, "offset", from->track[cur_track].offset);
		add_next_index_zval(track_arr, track);
	}
	handle = zend_list_insert(from, le_cdrom);
	array_init(to);
	add_assoc_resource(to, "handle", handle);
	zend_list_addref(handle);

	add_assoc_long(to, "id", from->id);
	add_assoc_long(to, "status", from->status);
	add_assoc_long(to, "numtracks", from->numtracks);
	add_assoc_long(to, "cur_track", from->cur_track);
	add_assoc_long(to, "cur_frame", from->cur_frame);
	add_assoc_zval(to, "track", track_arr);
	
	return 1;
}

static int refresh_cdrom2array(SDL_CD *from, zval *to) {
	zval *arr,*track;
	int cur_track;

	getArrayValueByString(*to,"track",&arr);

	add_assoc_long(to, "status", from->status);
	add_assoc_long(to, "numtracks", from->numtracks);
	add_assoc_long(to, "cur_track", from->cur_track);
	add_assoc_long(to, "cur_frame", from->cur_frame);

	for(cur_track=0;cur_track <= from->numtracks; cur_track++) {
		getArrayValueByIndex(*arr,cur_track,&track);
		add_assoc_long(track, "id", from->track[cur_track].id);
		add_assoc_long(track, "type", from->track[cur_track].type);
		add_assoc_long(track, "unused", from->track[cur_track].unused);
		add_assoc_long(track, "length", from->track[cur_track].length);
		add_assoc_long(track, "offset", from->track[cur_track].offset);
	}
	
	return 1;
}

static Uint32 php_sdl_timer_dispatcher(Uint32 interval, void *param) {
	php_sdl_timer *t;
	void ***tsrm_ls;
	zval *call;
	zval *params;
	zval *obj,*fun,*retval;
	Uint32 returns;

	//php_printf("Interval: %d\n",interval);
	t=(php_sdl_timer *)param;
	//php_printf("Timer id:%d\n",t->timer_id);
	call=t->callback;
	params=t->params;
	//php_printf("Callback: %X\n",call);
	//dumpaVar(*call);
	//php_printf("Dispatcher\n");
	MAKE_STD_ZVAL(retval);
	switch(Z_TYPE_P(call)) {
	case IS_ARRAY:
		//php_printf("Call is array\n");
		getArrayValueByIndex(*call,0,&obj);
		getArrayValueByIndex(*call,1,&fun);
		if (call_user_function(EG(function_table),&obj,fun,retval,1,&params TSRMLS_CC)) {
			// fail
			php_error(E_WARNING, "sdl_addTimer: callback failed");

		}
		break;
	case IS_STRING:
		//php_printf("Call is string\n");
		if (call_user_function(EG(function_table),NULL,call,retval,1,&params TSRMLS_CC)) {
			//fail
			php_error(E_WARNING, "sdl_addTimer: callback failed");
		}
		break;
	default:
		php_error(E_WARNING, "sdl_addTimer: callback not accepted");
		return 0;
		break;
	}
	convert_to_long(retval);

	returns=Z_LVAL_P(retval);
	//php_printf("Returns: %d\n",returns);
	//php_printf("Quit\n");
	return returns;
}
